<template>
  <div class="cesium-viewer-wapper">
    <div id="cesiumContainer" />
    <viewerSettingSidebar top="18em" :viewerSource="viewerSource" />
    <div class="tool-box-top-left">
      <div class="select-box-wrapper">
        <!-- <select-box :options="flyOptions" style="margin-right: 10px;" /> -->
        <a-radio-group v-model:value="seriesName" size="small" button-style="solid">
          <a-radio-button v-for="(e, i) in btns" :key="e" :value="e" style="min-width: 4em;text-align: center;">{{ e }}</a-radio-button>
        </a-radio-group>
      </div>
    </div>
    <GlobeRotater showTime :viewerSource="viewerSource" />
    <MousePosition show :viewerSource="viewerSource" />
  </div>
</template>

<script>
import * as Cesium from '@cesiumjs';
import { defineComponent, ref, watch, toRaw } from 'vue';
import { SelectBox, SliderBar } from '@components/widgets';
import { G3V } from '@g3x';
import { MousePosition, viewerSettingSidebar, GlobeRotater } from '@g3x/g3v/ui';
import {viewerMixin} from '@mixins';
import merge from '@g3x/utils/merge';

// import czmPath from './path.js';

const $g3vOptions = {
  // defaultViewRectangle: G3V.defaultViews.global.china.rectangle,
  viewers: [
    {
      dom: 'cesiumContainer',
      name: 'viewer1',
      title: 'viewer#01',
      viewer: {
        imagery: { type: 'arcgisImagery', options: { brightness: 1, show: true } },
        imageryProvider: null,
        terrain: { type: 'default', options: { requestVertexNormals: true, requestWaterMask: true } },
        terrainProvider: null,
        shadows: false,
        scene3DOnly: true,
        // sceneMode: Cesium.SceneMode.SCENE2D,
        animation: false
      },
      layers: [
        { type: 'osmImagery', options: { brightness: 1, show: false } },
        { type: 'arcgisStreetMap', options: { brightness: 1, show: false } },
        { type: 'bingMapsImagery', options: { brightness: 1, show: false } },
        { type: 'tdtIboMap', options: { brightness: 1, show: false } },
        { type: 'tdtImgAnno', options: { brightness: 1, show: false } },
        {
          type: 'graticule',
          options: {
            brightness: 1,
            show: true
          }
        }
      ],
      globe: {
        depthTestAgainstTerrain: true,
        enableLighting: false //启用以太阳为光源的地球
      },
      bottomContainer: false,
      navigation: {
        // defaultResetView: G3V.defaultViews.global.china.rectangle ,
        defaultResetView: null //flyHome
      },
      shortcutAction: false,
      hideLayers: false
    }
  ]
};

export default defineComponent({
  name: 'population', // 飞行动画
  mixins: [viewerMixin],
  components: { SelectBox, SliderBar, viewerSettingSidebar, GlobeRotater, MousePosition },
  props: {},
  setup() {
    const seriesName = ref('');
    return { seriesName };
  },
  data() {
    return {
      btns: []
    };
  },
  computed: {},
  watch: {},
  methods: {
    g3vOptionsGet(original) {
      // const g3vOptions = merge($g3vOptions, true);
      return $g3vOptions;
    },
    onViewerInited() {
      console.log('population onViewerInited');
    },
    initEffects() {
      const vm = this;
      const { viewer } = vm;
      const globe = viewer.scene.globe;

      /**
       * This class is an example of a custom DataSource.  It loads JSON data as
       * defined by Google's WebGL Globe, https://github.com/dataarts/webgl-globe.
       * @alias WebGLGlobeDataSource
       * @constructor
       *
       * @param {String} [name] The name of this data source.  If undefined, a name
       *                        will be derived from the url.
       *
       * @example
       * var dataSource = new Cesium.WebGLGlobeDataSource();
       * dataSource.loadUrl('sample.json');
       * viewer.dataSources.add(dataSource);
       */
      function WebGLGlobeDataSource(name) {
        //All public configuration is defined as ES5 properties
        //These are just the "private" variables and their defaults.
        this._name = name;
        this._changed = new Cesium.Event();
        this._error = new Cesium.Event();
        this._isLoading = false;
        this._loading = new Cesium.Event();
        this._entityCollection = new Cesium.EntityCollection();
        this._seriesNames = [];
        this._seriesToDisplay = undefined;
        this._heightScale = 10000000;
        this._entityCluster = new Cesium.EntityCluster();
      }

      Object.defineProperties(WebGLGlobeDataSource.prototype, {
        //The below properties must be implemented by all DataSource instances

        /**
         * Gets a human-readable name for this instance.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {String}
         */
        name: {
          get: function() {
            return this._name;
          }
        },
        /**
         * Since WebGL Globe JSON is not time-dynamic, this property is always undefined.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {DataSourceClock}
         */
        clock: {
          value: undefined,
          writable: false
        },
        /**
         * Gets the collection of Entity instances.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {EntityCollection}
         */
        entities: {
          get: function() {
            return this._entityCollection;
          }
        },
        /**
         * Gets a value indicating if the data source is currently loading data.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {Boolean}
         */
        isLoading: {
          get: function() {
            return this._isLoading;
          }
        },
        /**
         * Gets an event that will be raised when the underlying data changes.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {Event}
         */
        changedEvent: {
          get: function() {
            return this._changed;
          }
        },
        /**
         * Gets an event that will be raised if an error is encountered during
         * processing.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {Event}
         */
        errorEvent: {
          get: function() {
            return this._error;
          }
        },
        /**
         * Gets an event that will be raised when the data source either starts or
         * stops loading.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {Event}
         */
        loadingEvent: {
          get: function() {
            return this._loading;
          }
        },

        //These properties are specific to this DataSource.

        /**
         * Gets the array of series names.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {String[]}
         */
        seriesNames: {
          get: function() {
            return this._seriesNames;
          }
        },
        /**
         * Gets or sets the name of the series to display.  WebGL JSON is designed
         * so that only one series is viewed at a time.  Valid values are defined
         * in the seriesNames property.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {String}
         */
        seriesToDisplay: {
          get: function() {
            return this._seriesToDisplay;
          },
          set: function(value) {
            this._seriesToDisplay = value;

            //Iterate over all entities and set their show property
            //to true only if they are part of the current series.
            var collection = this._entityCollection;
            var entities = collection.values;
            collection.suspendEvents();
            for (var i = 0; i < entities.length; i++) {
              var entity = entities[i];
              entity.show = value === entity.seriesName;
            }
            collection.resumeEvents();
          }
        },
        /**
         * Gets or sets the scale factor applied to the height of each line.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {Number}
         */
        heightScale: {
          get: function() {
            return this._heightScale;
          },
          set: function(value) {
            if (value <= 0) {
              throw new Cesium.DeveloperError('value must be greater than 0');
            }
            this._heightScale = value;
          }
        },
        /**
         * Gets whether or not this data source should be displayed.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {Boolean}
         */
        show: {
          get: function() {
            return this._entityCollection;
          },
          set: function(value) {
            this._entityCollection = value;
          }
        },
        /**
         * Gets or sets the clustering options for this data source. This object can be shared between multiple data sources.
         * @memberof WebGLGlobeDataSource.prototype
         * @type {EntityCluster}
         */
        clustering: {
          get: function() {
            return this._entityCluster;
          },
          set: function(value) {
            if (!Cesium.defined(value)) {
              throw new Cesium.DeveloperError('value must be defined.');
            }
            this._entityCluster = value;
          }
        }
      });

      /**
       * Asynchronously loads the GeoJSON at the provided url, replacing any existing data.
       * @param {Object} url The url to be processed.
       * @returns {Promise} a promise that will resolve when the GeoJSON is loaded.
       */
      WebGLGlobeDataSource.prototype.loadUrl = function(url) {
        if (!Cesium.defined(url)) {
          throw new Cesium.DeveloperError('url is required.');
        }

        //Create a name based on the url
        var name = Cesium.getFilenameFromUri(url);

        //Set the name if it is different than the current name.
        if (this._name !== name) {
          this._name = name;
          this._changed.raiseEvent(this);
        }

        //Use 'when' to load the URL into a json object
        //and then process is with the `load` function.
        var that = this;
        return Cesium.Resource.fetchJson(url)
          .then(function(json) {
            return that.load(json, url);
          })
          .otherwise(function(error) {
            //Otherwise will catch any errors or exceptions that occur
            //during the promise processing. When this happens,
            //we raise the error event and reject the promise.
            this._setLoading(false);
            that._error.raiseEvent(that, error);
            return Cesium.when.reject(error);
          });
      };

      /**
       * Loads the provided data, replacing any existing data.
       * @param {Array} data The object to be processed.
       */
      WebGLGlobeDataSource.prototype.load = function(data) {
        //>>includeStart('debug', pragmas.debug);
        if (!Cesium.defined(data)) {
          throw new Cesium.DeveloperError('data is required.');
        }
        //>>includeEnd('debug');

        //Clear out any data that might already exist.
        this._setLoading(true);
        this._seriesNames.length = 0;
        this._seriesToDisplay = undefined;

        var heightScale = this.heightScale;
        var entities = this._entityCollection;

        //It's a good idea to suspend events when making changes to a
        //large amount of entities.  This will cause events to be batched up
        //into the minimal amount of function calls and all take place at the
        //end of processing (when resumeEvents is called).
        entities.suspendEvents();
        entities.removeAll();

        //WebGL Globe JSON is an array of series, where each series itself is an
        //array of two items, the first containing the series name and the second
        //being an array of repeating latitude, longitude, height values.
        //
        //Here's a more visual example.
        //[["series1",[latitude, longitude, height, ... ]
        // ["series2",[latitude, longitude, height, ... ]]

        // Loop over each series
        for (var x = 0; x < data.length; x++) {
          var series = data[x];
          var seriesName = series[0];
          var coordinates = series[1];

          //Add the name of the series to our list of possible values.
          this._seriesNames.push(seriesName);

          //Make the first series the visible one by default
          var show = x === 0;
          if (show) {
            this._seriesToDisplay = seriesName;
          }

          //Now loop over each coordinate in the series and create
          // our entities from the data.
          for (var i = 0; i < coordinates.length; i += 3) {
            var latitude = coordinates[i];
            var longitude = coordinates[i + 1];
            var height = coordinates[i + 2];

            //Ignore lines of zero height.
            if (height === 0) {
              continue;
            }

            var color = Cesium.Color.fromHsl(0.6 - height * 0.5, 1.0, 0.5);
            var surfacePosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0);
            var heightPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, height * heightScale);

            //WebGL Globe only contains lines, so that's the only graphics we create.
            var polyline = new Cesium.PolylineGraphics();
            polyline.material = new Cesium.ColorMaterialProperty(color);
            polyline.width = new Cesium.ConstantProperty(2);
            polyline.arcType = new Cesium.ConstantProperty(Cesium.ArcType.NONE);
            polyline.positions = new Cesium.ConstantProperty([surfacePosition, heightPosition]);

            //The polyline instance itself needs to be on an entity.
            var entity = new Cesium.Entity({
              id: seriesName + ' index ' + i.toString(),
              show: show,
              polyline: polyline,
              seriesName: seriesName //Custom property to indicate series name
            });

            //Add the entity to the collection.
            entities.add(entity);
          }
        }

        //Once all data is processed, call resumeEvents and raise the changed event.
        entities.resumeEvents();
        this._changed.raiseEvent(this);
        this._setLoading(false);
      };

      WebGLGlobeDataSource.prototype._setLoading = function(isLoading) {
        if (this._isLoading !== isLoading) {
          this._isLoading = isLoading;
          this._loading.raiseEvent(this, isLoading);
        }
      };

      //Now that we've defined our own DataSource, we can use it to load
      //any JSON data formatted for WebGL Globe.
      var dataSource = new WebGLGlobeDataSource();
      dataSource.loadUrl('//zzgis.com/cdn/3d/SampleData/population909500.json').then(function() {
        //After the initial load, create buttons to let the user switch among series.
        vm.btns = [...dataSource.seriesNames];
        watch(() => vm.seriesName, newVal => (dataSource.seriesToDisplay = newVal));
        vm.seriesName = vm.btns[0];
      });

      viewer.clock.shouldAnimate = false;
      viewer.dataSources.add(dataSource);
    }
  }
});
</script>

<style lang="less">
.cesium-viewer-wapper {
  .tool-box-left-top {
    display: flex;
    button {
      min-width: 5em;
      background-color: rgba(0, 0, 0, 0.75);
      border-color: rgba(0, 0, 0, 0);
      cursor: pointer;
      transition: all 500ms;
      &:hover {
        opacity: 0.75;
      }
      &.active {
        background-color: rgba(0, 20, 200, 0.75);
      }
    }
  }
}
</style>
